/*
 * DevicesIIC.c
 *
 *      Author: Honrun
 */

#include "n32g031.h"
#include "stdio.h"
#include "DevicesIIC.h"




void vIIC1Init(void)
{
    /** GPIO configuration and clock enable */
    GPIO_InitType GPIO_InitStructure = {0};
    I2C_InitType I2C_InitStructure = {0};


    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_I2C1, ENABLE);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);


    GPIO_InitStructure.Pin        = GPIO_PIN_10 | GPIO_PIN_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_AF_OD;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF6_I2C1;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);

    /** I2C periphral configuration */
    I2C_DeInit(I2C1);
    I2C_InitStructure.BusMode     = I2C_BUSMODE_I2C;
    I2C_InitStructure.FmDutyCycle = I2C_FMDUTYCYCLE_2;
    I2C_InitStructure.OwnAddr1    = 0xff;
    I2C_InitStructure.AckEnable   = I2C_ACKEN;
    I2C_InitStructure.AddrMode    = I2C_ADDR_MODE_7BIT;
    I2C_InitStructure.ClkSpeed    = 400000;
    I2C_Init(I2C1, &I2C_InitStructure);


    I2C_Enable(I2C1, ENABLE);

    // vIIC0DMAInit();

    // /* configure I2C timing */
    // i2c_timing_config(I2C0, 0, 0x4, 0);
    // i2c_master_clock_config(I2C0, 45, 45);
    // /* enable I2C */
    // i2c_enable(I2C0);
}


/*!
    \brief      reset i2c bus
    \param[in]  none
    \param[out] none
    \retval     none
*/
void vIIC1DeInit(void)
{
    GPIO_InitType GPIO_InitStructure = {0};

    /* configure SDA/SCL for GPIO */
    GPIO_ResetBits(GPIOB, GPIO_PIN_10);
    GPIO_ResetBits(GPIOB, GPIO_PIN_11);

    GPIO_InitStructure.Pin        = GPIO_PIN_10 | GPIO_PIN_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);

    __NOP();
    __NOP();
    __NOP();
    __NOP();
    __NOP();
    /* stop signal sda */
    GPIO_SetBits(GPIOB, GPIO_PIN_11);
    __NOP();
    __NOP();
    __NOP();
    __NOP();
    __NOP();
    /* stop signal scl */
    GPIO_SetBits(GPIOB, GPIO_PIN_10);

    /* connect I2C1_SCL/SDA */
    GPIO_InitStructure.GPIO_Mode  = GPIO_MODE_AF_OD;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF6_I2C1;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);
}

void vIIC1DMAInit(void)
{
    // DMA_InitType DMA_InitStructure = {0};
    // NVIC_InitType NVIC_InitStructure = {0};
    // uint8_t ucBute = 0;

    // RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);


    // /* DMA channel5 configuration ----------------------------------------------*/
    // DMA_DeInit(DMA_CH5);
    // DMA_InitStructure.PeriphAddr     = (uint32_t)&I2C2->DAT;
    // DMA_InitStructure.MemAddr        = (uint32_t)I2C2_Rx_Buffer;
    // DMA_InitStructure.Direction      = DMA_DIR_PERIPH_SRC;
    // DMA_InitStructure.BufSize        = BUFFER_SIZE;
    // DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    // DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    // DMA_InitStructure.PeriphDataSize = DMA_MemoryDataSize_Byte;
    // DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_Byte;
    // DMA_InitStructure.CircularMode   = DMA_MODE_NORMAL;
    // DMA_InitStructure.Priority       = DMA_PRIORITY_VERY_HIGH;
    // DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
    // DMA_Init(DMA_CH5, &DMA_InitStructure);
    // DMA_RequestRemap(DMA_REMAP_I2C2_RX,DMA,DMA_CH5,ENABLE);
    // /* DMA channel6 configuration ----------------------------------------------*/
    // DMA_DeInit(DMA_CH1);
    // DMA_InitStructure.PeriphAddr = (uint32_t)&I2C1->DAT;
    // DMA_InitStructure.MemAddr    = (uint32_t)I2C1_Tx_Buffer;
    // DMA_InitStructure.Direction  = DMA_DIR_PERIPH_DST;
    // DMA_InitStructure.Priority   = DMA_PRIORITY_HIGH;
    // DMA_Init(DMA_CH1, &DMA_InitStructure);
    // DMA_RequestRemap(DMA_REMAP_I2C1_TX,DMA,DMA_CH1,ENABLE);
}


/*!
    \brief      write more than one byte to the EEPROM with a single write cycle
    \param[in]  p_buffer: pointer to the buffer containing the data to be written to the EEPROM
    \param[in]  write_address: EEPROM's internal address to write to
    \param[in]  number_of_byte: number of bytes to write to the EEPROM
    \param[out] none
    \retval     none
*/
int8_t cI2CxWriteDatas(I2C_Module* I2Cx, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = NULL;
    int32_t timeout = 0, startCnt = 0;

    if(iLength <= 0)
        return -1;

    // vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;
    vI2CxBusReset = vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; I2C_GetFlag(I2Cx, I2C_FLAG_BUSY) != RESET; ++timeout)
    {
        if(timeout > I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X busy.\r\n", (int32_t)I2Cx);
            return -2;
        }
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt < I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X start out.\r\n", (int32_t)I2Cx);
            return -3;
        }

        I2C_GenerateStart(I2C1, ENABLE);

        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
        {
            if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_MODE_FLAG) != RESET)
            {
                break;
            }
        }

        /* send address */
        I2C_SendAddr7bit(I2Cx, usIDAddr, I2C_DIRECTION_SEND);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
        {
            if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_TXMODE_FLAG) != RESET)
            {
                break;
            }
        }

        if(timeout < I2C_BUSY_TIME_OUT)
            break;
    }

    /* send reg */
    I2C_SendData(I2Cx, usRegAddr);
    /* wait until the transmit data buffer is empty */
    for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
    {
        if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_DATA_SENDING) != RESET)
        {
            break;
        }
    }

    while((iLength--) > 0)
    {
        /* send data */
        I2C_SendData(I2Cx, *pBuffer++);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
        {
            if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_DATA_SENDING) != RESET)
            {
                break;
            }
        }
    }

    /* wait until the transmit data buffer is empty */
    for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
    {
        if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_DATA_SENDED) != RESET)
        {
            break;
        }
    }

    I2C_GenerateStop(I2C1, ENABLE);


    return 0;
}


/*!
    \brief      read data from the EEPROM
    \param[in]  p_buffer: pointer to the buffer that receives the data read from the EEPROM
    \param[in]  read_address: EEPROM's internal address to start reading from
    \param[in]  number_of_byte: number of bytes to reads from the EEPROM
    \param[out] none
    \retval     none
*/
int8_t cI2CxReadDatas(I2C_Module* I2Cx, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = NULL;
    int32_t timeout = 0, startCnt = 0;

    if(iLength <= 0)
        return -1;

    // vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;
    vI2CxBusReset = vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; I2C_GetFlag(I2Cx, I2C_FLAG_BUSY) != RESET; ++timeout)
    {
        if(timeout > I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X busy.\r\n", (int32_t)I2Cx);
            return -2;
        }
    }

    I2C_ConfigAck(I2Cx, DISABLE);

    /* 重试 N 次 */
    for(startCnt = 0; startCnt < I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
            printf("cI2C %08X start out.\r\n", (int32_t)I2Cx);
            return -3;
        }

        I2C_GenerateStart(I2C1, ENABLE);

        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
        {
            if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_MODE_FLAG) != RESET)
            {
                break;
            }
        }

        /* send address */
        I2C_SendAddr7bit(I2Cx, usIDAddr, I2C_DIRECTION_SEND);
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
        {
            if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_TXMODE_FLAG) != RESET)
            {
                break;
            }
        }

        if(timeout < I2C_BUSY_TIME_OUT)
            break;
    }

    /* send reg */
    I2C_SendData(I2Cx, usRegAddr);
    /* wait until the transmit data buffer is empty */
    for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
    {
        if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_DATA_SENDING) != RESET)
        {
            break;
        }
    }

    I2C_ConfigAck(I2Cx, ENABLE);

    I2C_GenerateStart(I2C1, ENABLE);

    /* wait until the transmit data buffer is empty */
    for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
    {
        if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_MODE_FLAG) != RESET)
        {
            break;
        }
    }

    /* send address */
    I2C_SendAddr7bit(I2Cx, usIDAddr, I2C_DIRECTION_RECV);
    /* wait until the transmit data buffer is empty */
    for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
    {
        if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_TXMODE_FLAG) != RESET)
        {
            break;
        }
    }

    while((iLength--) > 0)
    {
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
        {
            if(I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_RECVD_FLAG) != RESET)
            {
                break;
            }
        }

        /* rec data */
        *pBuffer++ = I2C_RecvData(I2Cx);
    }

    // /* wait until the transmit data buffer is empty */
    // for(timeout = 0; timeout < I2C_BUSY_TIME_OUT; ++timeout)
    // {
    //     if(I2C_GetFlag(I2Cx, I2C_EVT_MASTER_DATA_SENDED) != RESET)
    //     {
    //         break;
    //     }
    // }

    I2C_GenerateStop(I2C1, ENABLE);

    return 0;
}


// /**
//  * @brief  设置DMA的数据传输长度，并启动DMA传输
//  * @param  DMAy_Channelx：   相应DMA的通道
//            Length：          传输长度
//  * @retval 无
//  */
// static void vDMASetAddrAndLenthStart(uint32_t dma_periph, dma_channel_enum channelx, dma_subperipheral_enum sub_periph, int8_t cDirection, uint32_t uiMemoryAddress, uint32_t uiPeriphAddress, uint32_t uiLength)
// {
//     uint32_t uiTime = 0;

//     uiTime = 1000000;
//     /* Disable the peripheral */
//     dma_channel_disable(dma_periph, channelx);
//     while(((DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_CHEN) != 0) && (--uiTime));

//     /* 必须要清除所有中断状态，才允许使能DMA */
//     dma_interrupt_flag_clear(dma_periph, channelx, 0xFFFFFFFF);

//     /* configure memory base address */
//     dma_memory_address_config(dma_periph, channelx, 0, uiMemoryAddress);

//     /* configure peripheral base address */
//     dma_periph_address_config(dma_periph, channelx, uiPeriphAddress);

//     /* Configure DMA Stream data length */
//     dma_transfer_number_config(dma_periph, channelx, uiLength);

//     /* configure the direction of data transfer on the channel   */
//     dma_transfer_direction_config(dma_periph, channelx, cDirection);

//     /* DMA channel peripheral select */
//     dma_channel_subperipheral_select(dma_periph, channelx, sub_periph);

//     uiTime = 1000000;
//     /* Enable the Peripheral */
//     dma_channel_enable(dma_periph, channelx);
//     while(((DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_CHEN) == 0) && (--uiTime));
// }


// /*!
//     \brief      write more than one byte to the EEPROM with a single write cycle
//     \param[in]  p_buffer: pointer to the buffer containing the data to be written to the EEPROM
//     \param[in]  write_address: EEPROM's internal address to write to
//     \param[in]  number_of_byte: number of bytes to write to the EEPROM
//     \param[out] none
//     \retval     none
// */
// int8_t cI2CxDMAWriteDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
// {
//     void (*vI2CxBusReset)(void) = NULL;
//     dma_subperipheral_enum sub_periph;
//     int32_t timeout = 0, startCnt = 0;

//     if(iLength <= 0)
//         return -1;

//     vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

//     /* i2c master sends start signal only when the bus is idle */
//     for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET; ++timeout)
//     {
//         if(timeout > I2C_BUSY_TIME_OUT)
//         {
//             vI2CxBusReset();
//             printf("cI2C %08X busy.\r\n", i2c_periph);
//             return -2;
//         }
//     }

//     /* 重试 N 次 */
//     for(startCnt = 0; startCnt < I2C_START_OUT; ++startCnt)
//     {
//         if(startCnt >= I2C_START_OUT)
//         {
//             vI2CxBusReset();
//             printf("cI2C %08X start out.\r\n", i2c_periph);
//             return -3;
//         }

//         /* configure slave address */
//         i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_TRANSMIT);
//         /* configure number of bytes to be transferred */
//         i2c_transfer_byte_number_config(i2c_periph, iLength + 1);
//         /* disable I2C automatic end mode in master mode */
//         i2c_automatic_end_enable(i2c_periph);

//         /* clear I2C_TDATA register */
//         I2C_STAT(i2c_periph) |= I2C_STAT_TBE;

//         i2c_start_on_bus(i2c_periph);
//         /* wait until the transmit data buffer is empty */
//         for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
//         {
//             if(i2c_flag_get(i2c_periph, I2C_FLAG_TBE) != RESET)
//             {
//                 break;
//             }
//         }

//         /* send address */
//         i2c_data_transmit(i2c_periph, usRegAddr);
//         /* wait until the transmit data buffer is empty */
//         for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
//         {
//             if(i2c_flag_get(i2c_periph, I2C_FLAG_TI) != RESET)
//             {
//                 break;
//             }
//         }

//         if(timeout < I2C_BYTE_TIME_OUT)
//             break;
//     }

//     sub_periph = (i2c_periph == I2C0) ? DMA_SUBPERI1 : DMA_SUBPERI7;
//     vDMASetAddrAndLenthStart(DMA0, DMA_CH7, sub_periph, DMA_MEMORY_TO_PERIPH, (uint32_t)pBuffer, (uint32_t)&I2C_TDATA(i2c_periph), iLength);

//     // /* 等待DMA传输完成 */
//     // while((dma_flag_get(DMA0, DMA_CH7, DMA_FLAG_FTF) == RESET) && ((DMA_CHCTL(DMA0, DMA_CH7) & DMA_CHXCTL_CHEN) != 0));
//     // dma_flag_clear(DMA0, DMA_CH7, DMA_FLAG_FTF);

//     /* wait until the stop condition is finished */
//     for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_STPDET) == RESET; ++timeout)
//     {
//         if(timeout > (I2C_BYTE_TIME_OUT * iLength))
//         {
//             vI2CxBusReset();
//             printf("cI2C %08X stpdet.\r\n", i2c_periph);
//             return -5;
//         }
//     }

//     /* clear STPDET flag */
//     i2c_flag_clear(i2c_periph, I2C_FLAG_STPDET);

//     return 0;
// }

// /*!
//     \brief      read data from the EEPROM
//     \param[in]  p_buffer: pointer to the buffer that receives the data read from the EEPROM
//     \param[in]  read_address: EEPROM's internal address to start reading from
//     \param[in]  number_of_byte: number of bytes to reads from the EEPROM
//     \param[out] none
//     \retval     none
// */
// int8_t cI2CxDMAReadDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, uint8_t* pBuffer, int32_t iLength)
// {
//     void (*vI2CxBusReset)(void) = NULL;
//     dma_channel_enum channelx;
//     dma_subperipheral_enum sub_periph;
//     int32_t timeout = 0, startCnt = 0;

//     if(iLength <= 0)
//         return -1;

//     vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

//     /* i2c master sends start signal only when the bus is idle */
//     for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET; ++timeout)
//     {
//         if(timeout > I2C_BUSY_TIME_OUT)
//         {
//             vI2CxBusReset();
//             printf("cI2C %08X busy.\r\n", i2c_periph);
//             return -2;
//         }
//     }

//     /* 重试 N 次 */
//     for(startCnt = 0; startCnt < I2C_START_OUT; ++startCnt)
//     {
//         if(startCnt >= I2C_START_OUT)
//         {
//             vI2CxBusReset();
//             printf("cI2C %08X start timeout.\r\n", i2c_periph);
//             return -3;
//         }

//         /* clear I2C_TDATA register */
//         I2C_STAT(i2c_periph) |= I2C_STAT_TBE;

//         /* configure slave address */
//         i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_TRANSMIT);
//         /* configure number of bytes to be transferred */
//         i2c_transfer_byte_number_config(i2c_periph, 1);
//         /* disable I2C automatic end mode in master mode */
//         i2c_automatic_end_disable(i2c_periph);

//         i2c_start_on_bus(i2c_periph);
//         /* wait until the transmit data buffer is empty */
//         for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
//         {
//             if(i2c_flag_get(i2c_periph, I2C_FLAG_TBE) != RESET)
//             {
//                 break;
//             }
//         }

//         /* send address */
//         i2c_data_transmit(i2c_periph, usRegAddr);
//         /* wait until the transmit data buffer is empty */
//         for(timeout = 0; timeout < I2C_BYTE_TIME_OUT; ++timeout)
//         {
//             if(i2c_flag_get(i2c_periph, I2C_FLAG_TC) != RESET)
//             {
//                 break;
//             }
//         }

//         if(timeout < I2C_BYTE_TIME_OUT)
//             break;
//     }

//     /* configure one byte address */
//     i2c_master_addressing(i2c_periph, usIDAddr, I2C_MASTER_RECEIVE);
//     /* configure number of bytes to be transferred */
//     i2c_transfer_byte_number_config(i2c_periph, iLength);
//     /* enable I2C automatic end mode in master mode */
//     i2c_automatic_end_enable(i2c_periph);

//     channelx = (i2c_periph == I2C0) ? DMA_CH0 : DMA_CH2;
//     sub_periph = (i2c_periph == I2C0) ? DMA_SUBPERI1 : DMA_SUBPERI7;
//     vDMASetAddrAndLenthStart(DMA0, channelx, sub_periph, DMA_PERIPH_TO_MEMORY, (uint32_t)pBuffer, (uint32_t)&I2C_RDATA(i2c_periph), iLength);

//     /* restart */
//     i2c_start_on_bus(i2c_periph);

//     // /* 等待DMA传输完成 */
//     // while((dma_flag_get(DMA0, channelx, DMA_FLAG_FTF) == RESET) && ((DMA_CHCTL(DMA0, channelx) & DMA_CHXCTL_CHEN) != 0));
//     // dma_flag_clear(DMA0, channelx, DMA_FLAG_FTF);

//     /* wait until the stop condition is finished */
//     for(timeout = 0; i2c_flag_get(i2c_periph, I2C_FLAG_STPDET) == RESET; ++timeout)
//     {
//         if(timeout > (I2C_BYTE_TIME_OUT * iLength))
//         {
//             vI2CxBusReset();
//             printf("cI2C %08X stpdet.\r\n", i2c_periph);
//             return -5;
//         }
//     }

//     /* clear STPDET flag */
//     i2c_flag_clear(i2c_periph, I2C_FLAG_STPDET);

//     return 0;
// }
